package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotations.*;
import net.sf.cglib.core.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 生成对象的工厂
 */
public class BeanFactory {

    /**
     * Ioc容器
     * key:配置文件的id
     * value:实例化好了的对象
     */
    private static Map<String, Object> beanMap = new HashMap<>();


    static {
        ClassLoader classLoader = BeanFactory.class.getClassLoader();
        //1. 使用类加载器读取配置文件
        InputStream inputStream = classLoader.getResourceAsStream("beans.xml");
        //2. 使用dom4j解析配置文件
        SAXReader saxReader = new SAXReader();
        try {
            //2.1 获取到根对象<beans>标签
            Document document = saxReader.read(inputStream);
            //3. 解析注解
            //获取包扫描配置
            List<Element> contextList = document.selectNodes("//component-scan");
            if (!contextList.isEmpty()) {
                Element element = contextList.get(0);
                //获取包路径
                String packagePath = element.attributeValue("base-package");
                //扫描包
                Reflections reflections = new Reflections(packagePath);

                //获取包下所有注解类
                Set<Class<?>> repositorySet = reflections.getTypesAnnotatedWith(Repository.class);
                for (Class<?> clazz : repositorySet) {
                    //判断注解是否有属性值
                    Repository repository = clazz.getAnnotation(Repository.class);
                    String name = repository.value();
                    if (StringUtils.isEmpty(name)) {
                        //没有属性值,默认类名首字母小写
                        name = clazz.getName();
                        name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    }
                    beanMap.put(name, clazz.newInstance());
                }

                Set<Class<?>> serviceSet = reflections.getTypesAnnotatedWith(Service.class);
                for (Class<?> clazz : serviceSet) {

                    Service service = clazz.getAnnotation(Service.class);
                    String name = service.value();
                    if (StringUtils.isEmpty(name)) {
                        name = clazz.getName();
                        name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    }
                    beanMap.put(name, clazz.newInstance());
                }

                Set<Class<?>> componentSet = reflections.getTypesAnnotatedWith(Component.class);
                for (Class<?> clazz : componentSet) {
                    Component component = clazz.getAnnotation(Component.class);
                    String name = component.value();
                    if (StringUtils.isEmpty(name)) {
                        name = clazz.getName();
                        name = name.substring(0, 1).toLowerCase() + name.substring(1);
                    }
                    beanMap.put(name, clazz.newInstance());
                }

                //维护依赖关系
                for (String id : beanMap.keySet()) {
                    Object object = beanMap.get(id);
                    Class<?> aClass = object.getClass();
                    Field[] declaredFields = aClass.getDeclaredFields();
                    for (Field declaredField : declaredFields) {
                        //获取有注解的属性
                        Autowired autowired = declaredField.getAnnotation(Autowired.class);
                        if (autowired != null) {
                            String name = declaredField.getName();
                            name = name.substring(0, 1).toLowerCase() + name.substring(1);
                            declaredField.setAccessible(true);
                            //对象中注入属性
                            declaredField.set(object, beanMap.get(name));
                        }
                    }
                }

                //获取代理工厂类
                ProxyFactory proxyFactory = (ProxyFactory) beanMap.get("proxyFactory");

                //管理事务
                for (String id : beanMap.keySet()) {
                    Object object = beanMap.get(id);
                    Class<?> aClass = object.getClass();
                    //类上
                    if (aClass.getAnnotation(Transactional.class) != null) {
                        object = proxyFactory.getProxy(object);
                    }
                    beanMap.put(id, object);
                }
                System.out.println(beanMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 提供对外获取对象的接口
     *
     * @param id
     * @return
     */
    public static Object getBean(String id) {
        return beanMap.get(id);
    }
}
